//
//  46.孩子们的游戏(圆圈中最后剩下的数).swift
//  数据结构与算法
//
//  Created by ZERO on 2021/5/29.
//

import Foundation
/*
 题目：每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0...m-1报数....这样下去....直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!^_^)。请你试着想下,哪个小朋友会得到这份礼品呢？(注：小朋友的编号是从0到n-1)
     如果没有小朋友，请返回-1
 思路1：模拟法，把小孩编到数组里，每次出去一个删一个，记录出去的下标，删除一个后，当前下标即为下一个小孩的下标
      下标超过剩下的孩子数组大小，直接对数组大小取余
 思路2：递归法，假设f(n, m) 表示最终留下元素的序号。比如上例子中表示为:f(5,3) = 3
       首先，长度为 n 的序列会先删除第 m % n 个元素，然后剩下一个长度为 n - 1 的序列。那么，我们可以递归地求解 f(n - 1, m)，就可以知道对于剩下的 n - 1 个元素，最终会留下第几个元素，我们设答案为 x = f(n - 1, m)。
       由于我们删除了第 m % n 个元素，将序列的长度变为 n - 1。当我们知道了 f(n - 1, m) 对应的答案 x 之后，我们也就可以知道，长度为 n 的序列最后一个删除的元素，应当是从 m % n 开始数的第 x 个元素。因此有 f(n, m) = (m % n + x) % n = (m + x) % n。
       当n等于1时，f(1,m) = 0
 思路3：迭代法，根据方法二可知，
       f[1] = 0
       f[2] = (f{1] + m) % 2
       f[3] = (f[2] + m) % 3
       ...
       f[n] = (f[n-1] + m) % n
 */
func offer_46() {
    print(Solution().LastRemaining_Solution3(5,3))
}

fileprivate class Solution {
    func LastRemaining_Solution1(_ n: Int, _ m: Int) -> Int {
        guard n > 0 else { return -1 }
        var kids = Array(0..<n)
        var firstIndex = 0
        while kids.count > 1 {
//            firstIndex += m - 1
//            if firstIndex >= kids.count {
//                firstIndex %= kids.count
//            }
            firstIndex = (firstIndex + m - 1) % kids.count
            kids.remove(at: firstIndex)
        }
        return kids.first!
    }
    
    func LastRemaining_Solution2(_ n: Int, _ m: Int) -> Int {
        guard n > 0 else { return -1 }
        
        func f(_ n: Int, _ m: Int) -> Int {
            if n == 1 { return 0 }
            let x = f(n - 1, m)
            return (x + m) % n
        }
        
        return f(n, m)
    }
    
    func LastRemaining_Solution3(_ n: Int, _ m: Int) -> Int {
        guard n > 0 else { return -1 }
        var index = 0
        for i in 2...n {
            index = (index + m) % i
        }
        return index
    }
}


